package net
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.Socket;
	import flash.utils.Dictionary;
	import flash.utils.Endian;
	
	import globals.$log;
	
	public class Server
	{
		public static const HEAD_LENGTH:int = 4;
		
		public var _socket:Socket;
		public var _expectLength:int = HEAD_LENGTH;
		public var _readingDataLength:Boolean = true;
		public var _readBuffer:Stream;
		public var _writeBuffer:Stream;
		
		public var _msgHandlers:Dictionary = new Dictionary();
		
		public function Server(buflen:int=1024)
		{
			_readBuffer = new Stream;
			_readBuffer.length = buflen;
			_writeBuffer = new Stream;
			_writeBuffer.length = buflen;
		}
		
		public function connect(host:String, port:int, endian:String=Endian.LITTLE_ENDIAN):void {
			_readBuffer.endian = endian;			
			_writeBuffer.endian = endian;			
			_expectLength = HEAD_LENGTH;
			_readingDataLength = true;
			if (_socket != null) {
				_socket.close();
				_socket = null;
			}
			_socket = new Socket();
			_socket.endian= endian;
			_socket.addEventListener(Event.CONNECT, onConnect);
			_socket.addEventListener(ProgressEvent.SOCKET_DATA, onData);
			_socket.addEventListener(Event.CLOSE, onServerClose);
			_socket.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			_socket.connect(host, port);
			$log.info("connecting to " + host + ":" + port);	
		}
		
		public function onConnect(e:Event):void {
			$log.info("connect success ");
		}
		
		public function onServerClose(e:Event):void {
			$log.error(e);
			_socket.close();
			_socket = null;
		}
		
		public function onIOError(e:Event):void {
			$log.error(e);
			_socket.close();
			_socket = null;
		}
		
		public function onSecurityError(e:Event):void {
			$log.error(e);
			_socket.close();
			_socket = null;
		}
		
		public function onData(e:Event):void {
			while (_socket.connected && _expectLength <= _socket.bytesAvailable) {
				if (_readingDataLength) {
					_expectLength = _socket.readInt();
					_readingDataLength = false;
				} else {
					_readBuffer.position = 0;
					_socket.readBytes(_readBuffer, 0, _expectLength);
					_readBuffer.position = 0;
					handleData(_readBuffer);					
					_expectLength = HEAD_LENGTH;
					_readingDataLength = true;					
				}
			}
		}
		
		public function handleData(data:Stream):void {
			var msg:String = data.readStringX();
			if (_msgHandlers[msg] != null) {
				_msgHandlers[msg](data);
			}
		}
		
		public function setMessageHandler(name:String, func:Function):void {
			_msgHandlers[name] = func;
		}
		
		public function removeMessageHandler(name:String):void {
			delete _msgHandlers[name];
		}
		
		public function startMsg(name:String):Stream {
			if (_socket == null) {
				$log.error("not connect a server");
				return null;
			}
			_writeBuffer.position = 4;
			_writeBuffer.writeStringX(name);
			$log.info("sending msg " + name);
			return _writeBuffer;
		}
		
		public function sendMsg():void {
			var dataLen:int = _writeBuffer.position-HEAD_LENGTH;			
			_writeBuffer.position = 0;
			_writeBuffer.writeInt(dataLen);
			_writeBuffer.position = 0;
			_socket.writeBytes(_writeBuffer, 0, dataLen+HEAD_LENGTH);
			_socket.flush();
		}
		
	}
}